/**
 * FloatTexture implementation
 */

#include "FloatTexture.h"

ProgramPtr FloatTexture::_quadProg((Program*)0);

/////////////////////////////////////////////////

FloatTexture::FloatTexture(const std::string& name, const Vec2s& s) 
//			: Texture(name, s, GL_TEXTURE_RECTANGLE_NV, GL_FLOAT_RGBA32_NV), _pixels(0)
			: Texture(name, s, GL_TEXTURE_RECTANGLE_NV, GL_FLOAT_RGBA16_NV), _pixels(0)
{
	glEnable(_target);
	glBindTexture(_target, _glName);
	glTexImage2D(_target, 0, _intFormat, _size[0], _size[1], 
			0, GL_RGBA, GL_FLOAT, 0);
	glTexParameteri(_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameteri(_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri(_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
	checkGLError();

	glBindTexture(_target, 0);
	glDisable(_target);

	createQuadProgram();
}

/////////////////////////////////////////////////

void FloatTexture::drawFullScreen()
{
    //seperated for MRT, need to call bind on FBO after load on Program
    drawFullScreen_begin();
    drawFullScreen_end();
}

void FloatTexture::drawFullScreen_begin()
{
	_quadProg->load();
}
void FloatTexture::drawFullScreen_end()
{
	//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	checkGLError();

    //done above
	//_quadProg->load();
	_quadProg->setSampler("tex", 0);

	glActiveTexture(GL_TEXTURE0);
	glEnable(_target);
	glBindTexture(_target, _glName);
	checkGLError();

	glBegin(GL_QUADS);
	// When using TEXTURE_RECTANGLE_NV, tex coords are not normalized 
	glTexCoord2i(0, 0);
	glVertex3f(-1.0, -1.0, 0.0);
	
	glTexCoord2i(_size[0], 0);
	glVertex3f(1.0, -1.0, 0.0);
	
	glTexCoord2i(_size[0], _size[1]);
	glVertex3f(1.0, 1.0, 0.0);
	
	glTexCoord2i(0, _size[1]);
	glVertex3f(-1.0, 1.0, 0.0);
	glEnd();

	glBindTexture(_target, 0);
	glDisable(_target);
	checkGLError();

	_quadProg->unload();
}

////////////////////////////////////////////////

void FloatTexture::createQuadProgram()
{
	if (_quadProg != 0) return;

	char* vertC = 
		"void main() {	"
		"	gl_TexCoord[0] = gl_MultiTexCoord0;"
		"	gl_Position = gl_Vertex;"
		"}";
	char* fragC =
		"uniform samplerRect tex;"
		"void main (void) {"
		"	vec2 c = gl_TexCoord[0].st;"
		"	gl_FragData[0] = textureRect(tex, c);"
		"	gl_FragData[1] = textureRect(tex, c);"
		"}";

	ShaderPtr vert(new Shader(std::string("vert"), vertC, GL_VERTEX_SHADER));
	ShaderPtr frag(new Shader(std::string("frag"), fragC, GL_FRAGMENT_SHADER));
	ProgramPtr p(new Program("full screen float quad", vert, frag));
	_quadProg = p;
}

/////////////////////////////////////////////////

void FloatTexture::readPixels()
{
	// TODO worry about read buffer?
	if (_pixels == 0) {
		_pixels = new GLfloat[_size[0]*_size[1]*4];
	}
	assert(_pixels);
	glReadPixels(0, 0, _size[0], _size[1], GL_RGBA, GL_FLOAT, _pixels);
	checkGLError();
}

/////////////////////////////////////////////////

Vec4 FloatTexture::getPixel(Vec2s at)
{
	assert(_pixels);
	assert(at[0] < _size[0]);
	assert(at[1] < _size[1]);
	Vec4 c;
	c[0] = _pixels[at[1]*_size[0]*4 + at[0]*4 + 0];
	c[1] = _pixels[at[1]*_size[0]*4 + at[0]*4 + 1];
	c[2] = _pixels[at[1]*_size[0]*4 + at[0]*4 + 2];
	c[3] = _pixels[at[1]*_size[0]*4 + at[0]*4 + 3];
	return c;
}

/////////////////////////////////////////////////

FloatTexture::~FloatTexture()
{
	if (_pixels) {
		delete[] _pixels;
	}
}

